package com.ysstech.common.realm;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import com.ysstech.common.annotation.YssPermissions;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresGuest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.springframework.core.annotation.AnnotationUtils;

public class YssAuthorizationAttributeSourceAdvisor extends AuthorizationAttributeSourceAdvisor {

    private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
            new Class[]{YssPermissions.class, RequiresPermissions.class, RequiresRoles.class,
                    RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class};

    public YssAuthorizationAttributeSourceAdvisor() {
        setAdvice(new YssAopAllianceAnnotationsAuthorizingMethodInterceptor());
    }


    public boolean matches(Method method, @SuppressWarnings("rawtypes") Class targetClass) {
        Method m = method;

        if (isAuthzAnnotationPresent(m)) {
            return true;
        }

        //The 'method' parameter could be from an interface that doesn't have the annotation.
        //Check to see if the implementation has it.
        if (targetClass != null) {
            try {
                m = targetClass.getMethod(m.getName(), m.getParameterTypes());
                if (isAuthzAnnotationPresent(m)) {
                    return true;
                }
            } catch (NoSuchMethodException ignored) {
                //default return valueMoney is false.  If we can't find the method, then obviously
                //there is no annotation, so just use the default return valueMoney.
            }
        }
        return false;
    }

    private boolean isAuthzAnnotationPresent(Class<?> targetClazz) {
        Class[] authzAnnotationClasses = AUTHZ_ANNOTATION_CLASSES;
        for (int i = 0; i < authzAnnotationClasses.length; ++i) {
            Class<? extends Annotation> annClass = authzAnnotationClasses[i];
            Annotation a = AnnotationUtils.findAnnotation(targetClazz, annClass);
            if (a != null) {
                return true;
            }
        }
        return false;
    }

    private boolean isAuthzAnnotationPresent(Method method) {
        for (Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
            Annotation a = AnnotationUtils.findAnnotation(method, annClass);
            if (a != null) {
                return true;
            }
        }
        return false;
    }
}
